package uk.co.q3c.deplan.client.service;

import java.io.Serializable;
import java.util.Date;

import javax.persistence.Id;

import uk.co.q3c.deplan.client.domain.AbstractDomainObject;
import uk.co.q3c.deplan.client.domain.DomainKind;
import uk.co.q3c.deplan.client.domain.DomainObject;
import uk.co.q3c.deplan.client.domain.resource.PersistenceReferenceException;

import com.googlecode.objectify.Key;
import com.googlecode.objectify.annotation.Cached;
import com.googlecode.objectify.annotation.Unindexed;

@Unindexed
@Cached(expirationSeconds = 600)
public class PlanManager extends AbstractDomainObject implements Serializable {

	private static final long serialVersionUID = 1L;
	@Id
	private Long keyId;
	private Date planEnd;
	private Date currentDate;
	/**
	 * The number of days to plan work for (from currentDate)
	 */
	int horizon = 365;

	protected PlanManager() {
		super();

	}

	public PlanManager(ServiceFactory connection) {
		super(connection);

	}

	/**
	 * A property change 'planEnd' is fired.
	 * 
	 * @param newPlanEnd
	 */
	private void setPlanEnd(Date newPlanEnd) {

		Date oldValue = new Date(this.planEnd.getTime());
		this.planEnd.setTime(newPlanEnd.getTime());
		firePropertyChange("planEnd", oldValue, this.planEnd);
	}

	/**
	 * Makes sure there is a date object for {@link #planEnd}
	 */
	@Override
	protected void beforeLoad() {
		if (planEnd == null) {
			planEnd = new Date();
		}
	}

	/**
	 * Gets {@link #horizon}
	 */
	public int getHorizon() {

		return horizon;
	}

	/**
	 * 
	 * Sets {@link #horizon} and calls {@link #calculatePlanEnd()}. Values < 1 are ignored. Fires property change.
	 */
	public void setHorizon(int horizon) {
		if (horizon >= 1) {

			int oldValue = this.horizon;
			this.horizon = horizon;
			firePropertyChange("horizon", oldValue, this.horizon);
			calculatePlanEnd();
		}
	}

	public Date getPlanEnd() {

		return planEnd;
	}

	/**
	 * // * recalculates the new plan end date (currentDate + horizon - 1), then calls {@link #setPlanEnd(Date)}. //
	 */
	// public void calculatePlanEnd() {
	// GregorianCalendar cal = new GregorianCalendar();
	// cal.setTime(getCurrentDate());
	// cal.add(Calendar.DAY_OF_YEAR, horizon - 1);
	// setPlanEnd(cal.getTime());
	//
	// }

	@SuppressWarnings("deprecation")
	public void calculatePlanEnd() {
		Date d = new Date(getCurrentDate().getTime());
		d.setDate(d.getDate() + horizon - 1);
		setPlanEnd(d);
	}

	/**
	 * Returns current date. If currentDate is null, sets it to 'now' before returning it.
	 * 
	 * @return
	 */
	public Date getCurrentDate() {

		if (currentDate == null) {
			currentDate = new Date();
		}
		return currentDate;
	}

	@Override
	public DomainKind getKind() {
		return DomainKind.PlanManager;
	}

	public Long getKeyId() {
		return keyId;
	}

	@Override
	public Key<? extends DomainObject> getKey() throws PersistenceReferenceException {
		throw new RuntimeException("Not yet implemented");
	}

	@Override
	public void setKeyId(Long keyId) {
		throw new RuntimeException("Not yet implemented");
	}
}
